#!/usr/bin/python3
#-*-coding:utf-8-*-

###############################################################
## Name       : gen_tb
## Author     : gaojiaming
## Date       : Tue Nov 29 22:26:14 CST 2022
## Description:
##
##
###############################################################

import sys
import os
import re
import argparse

class Model:#{{{
    def __init__(self, parent, name, inst, type, create, connect):
        self.parent  = parent
        self.name    = name
        self.inst    = inst
        self.type    = type
        self.create  = create
        self.connect = connect

    def state_str(self, head = "  "):
        str = ""
        str+= head + "{0} {1};\n".format(self.name, self.inst)
        return str

    def create_str(self, head = "  "):
        str = ""
        if re.search(r"AGENT", self.type):
            res0 = re.search(r"AGENT::(\w+)", self.type)
            res1 = re.search(r"(\w+)\[(\d+)\]", self.inst)
            if res1: #a_scb[8]
                inst   = res1.group(1)
                repeat = res1.group(2)
                str+= head + "for(int i=0;i<{0};i=i+1)begin\n".format(repeat)
                str+= head + "  {0}[i] = {1}::type_id::create($sformatf(\"{0}[%0d]\", i), this);\n".format(inst, self.name)
                str+= head + "  {0}[i].is_active = {1};\n".format(inst, res0.group(1))
                str+= head + "end\n"
            else:
                str+= head + "{0} = {1}::type_id::create(\"{0}\", this);\n".format(self.inst, self.name)
                str+= head + "{0}.is_active = {1};\n".format(self.inst, res0.group(1))
        elif self.type == "MODEL" or self.type == "SCB" or self.type == "VSQR":
            res = re.search(r"(\w+)\[(\d+)\]", self.inst)
            if res: #a_scb[8]
                inst   = res.group(1)
                repeat = res.group(2)
                str+= head + "for(int i=0;i<{0};i=i+1)begin\n".format(repeat)
                str+= head + "  {0}[i] = {1}::type_id::create($sformatf(\"{0}[%0d]\", i), this);\n".format(inst, self.name)
                str+= head + "end\n"
            else:
                str+= head + "{0} = {1}::type_id::create(\"{0}\", this);\n".format(self.inst, self.name)
            if self.type == "VSQR":
                str+= head + "uvm_config_db #(uvm_object_wrapper)::set(\n"
                str+= head + "  this,\n"
                str+= head + "  \"{0}.main_phase\",\n".format(self.inst)
                str+= head + "  \"default_sequence\",\n"
                str+= head + "  {0}::type_id::get()\n".format(re.sub(r"vsqr", "seq", self.name))
                str+= head + ");\n"
        elif self.type == "RAL":
            str+= head + "if(!uvm_config_db #({0})::get(this, \"\", \"{1}\", {1})) begin\n".format(self.name, self.inst)
            str+= head + "  {0} = {1}::type_id::create(\"{0}\", this);\n".format(self.inst, self.name)
            str+= head + "  {0}.build();\n".format(self.inst)
            str+= head + "  {0}.lock_model();\n".format(self.inst)
            str+= head + "  {0}.reset();\n".format(self.inst)
            str+= head + "end\n"
            str+= head + "adapter = apb_adapter::type_id::create(\"adapter\", this);\n"
        return str
#}}}

def input_cfg_file():#{{{
    if len(sys.argv) <= 1:
        print("ERROR: You need input a agent name")
        sys.exit()
    tb_name = sys.argv[1]
    tb_cfg_file = tb_name + ".cfg"
    if not os.path.exists(tb_cfg_file):
        os.system("cp {0}/gen_tb.cfg ./{1}".format(root_path, tb_cfg_file))
        os.system("gvim ./{}".format(tb_cfg_file))
        rsp=input("Please input y after complete: ")
        if rsp != "y":
            print("ERROR: You need input a agent cfg_file")
            sys.exit()
    return tb_name, tb_cfg_file
#}}}

def sys_cfg_file(cfg_file):
    env_mdl_list = []
    base_mdl_list = []
    with open(cfg_file, "r") as hd:
        handle = hd.readlines()
        for line in handle:
            if not re.search(r"^\s*//", line):
                arr = line.split("|")
                parent = arr[0].strip()
                name   = arr[1].strip()
                inst   = arr[2].strip()
                type   = arr[3].strip()
                create = arr[4].strip()
                connect= arr[5].strip()
                model = Model(parent, name, inst, type, create, connect)
                if parent == "env":
                    env_mdl_list.append(model)
                else:
                    base_mdl_list.append(model)
    return env_mdl_list, base_mdl_list
pass

def gen_env(tb_name, mdl_list):
    env_str = ""
    with open("{0}/tb_dict/env/tb_env.sv".format(root_path), "r") as hd:
        handle = hd.readlines()
        for line in handle:
            line = re.sub(r"tb_env", "{0}_env".format(tb_name), line)
            line = re.sub(r"TB_ENV", "{0}_ENV".format(tb_name.upper()), line)
            if re.search(r"\/\*STATE_POSI\*\/", line):
                for mdl in mdl_list:
                    env_str+= mdl.state_str()
            elif re.search(r"\/\*CREATE_POSI\*\/", line):
                for mdl in mdl_list:
                    env_str+= mdl.create_str()
            else:
                env_str+=line
    return env_str
pass

def gen_base(tb_name, mdl_list):
    env_str = ""
    with open("{0}/tb_dict/tc/base_test.sv".format(root_path), "r") as hd:
        handle = hd.readlines()
        for line in handle:
            if re.search(r"\/\*STATE_POSI\*\/", line):
                for mdl in mdl_list:
                    env_str+= mdl.state_str()
            elif re.search(r"\/\*CREATE_POSI\*\/", line):
                for mdl in mdl_list:
                    env_str+= mdl.create_str()
            else:
                env_str+=line
    return env_str
pass

def mkdir_dict(tb_name, env, base):
    os.system("mkdir -p {0}".format(tb_name))
    os.system("mkdir -p {0}/tc".format(tb_name))
    os.system("mkdir -p {0}/env".format(tb_name))
    os.system("cp {0}/tb_dict/cfg ./{1}/ -rf".format(root_path, tb_name))
    os.system("cp {0}/tb_dict/sim ./{1}/ -rf".format(root_path, tb_name))
    os.system("cp {0}/tb_dict/th  ./{1}/ -rf".format(root_path, tb_name))
    os.system("cp {0}/tb_dict/tc  ./{1}/ -rf".format(root_path, tb_name))
    with open("./{0}/env/{0}_env.sv".format(tb_name), "w") as hd:
        hd.write(env)
    with open("./{0}/tc/base_test.sv".format(tb_name), "w") as hd:
        hd.write(base)
pass

def main():
    (tb_name, tb_cfg_file) = input_cfg_file()
    (env_mdl_list, base_mdl_list) = sys_cfg_file(tb_cfg_file)
    env = gen_env(tb_name, env_mdl_list)
    base = gen_base(tb_name, base_mdl_list)
    mkdir_dict(tb_name, env, base)
pass

if __name__ == "__main__":
    print("%s is working" % __file__)
    global root_path
    global work_path
    root_path = sys.path[0]
    work_path = os.path.abspath('.')
    main()
